﻿using System.Collections.Generic;
using System;
using System.Text;

namespace Ex03.GarageLogic
{
    /// <summary>
    /// This class is for a Motorcycle Wheel
    /// </summary>
    public class Wheel
    {
        public const string k_Delimiter = " ";
        private const string k_WheelNumberKey = "Wheel Number";
        private const string k_WheelManufacturerKey = "Wheel Manufacturer";
        private const string k_MaxAirPressureKey = "Max Air Pressure";
        private const string k_CurrentAirPressureKey = "Current Air Pressure";
        private const float k_MinAirPressure = 0.0f;
        private readonly float r_MaxAirPressure;

        private string m_Manufacturer;
        private float m_CurrentAirPressure;
        private int m_WheelNumber;

        /// <summary>
        /// A static method to create a wheel form
        /// </summary>
        /// <param name="i_NumOfWheels">
        /// The number of Wheel in the resulting form
        /// <remarks>
        ///     Will return null if input is smaller of equal to zero
        /// </remarks> 
        /// </param>
        /// <returns></returns>
        public static Dictionary<string, string> CreateWheelsForm(int i_NumOfWheels)
        {
            Dictionary<string, string> resultForm = null;
            if (i_NumOfWheels > 0)
            {
                resultForm = new Dictionary<string, string>();
            }

            for (int i = 1; i <= i_NumOfWheels; ++i)
            {
                resultForm.Add(k_WheelManufacturerKey + k_Delimiter + i, null);
                resultForm.Add(k_CurrentAirPressureKey + k_Delimiter + i, null);
            }

            return resultForm;
        }

        /// <summary>
        /// A constructor for the Car Data
        /// </summary>
        /// <param name="i_CreationForm">
        /// A key value Dictionary where key is the name of the member 
        /// to initialize and value is the new value
        /// <remarks>
        ///     The input form Must have a license type property and an engine capacity property
        ///     the input Must be "pars-able" to eLicenseType and of int
        ///     else will throw FormatException
        /// </remarks>
        /// </param>
        /// <summary>
        /// A constructor for the Wheel
        /// </summary>
        /// <param name="i_MaxAirPressure">
        /// The max air pressure
        /// <remarks>
        ///     Mast be greater then zero else will throw ArgumentException
        /// </remarks>
        /// </param>
        /// <param name="i_WheelNumber">
        /// The wheel number. Its index with regard to all other wheels of the 
        /// car
        /// <remarks>
        ///     Mast be greater then zero else will throw ArgumentException
        /// </remarks>
        /// </param>
        public Wheel(float i_MaxAirPressure, int i_WheelNumber)
        {
            if (i_MaxAirPressure <= 0.0f)
            {
                throw new ArgumentException("Max air pressure in wheels of vehicle is invalid (below zero)");
            }

            if (i_WheelNumber <= 0)
            {
                throw new ArgumentException("Wheel index is invalid (below zero)");
            }

            r_MaxAirPressure = i_MaxAirPressure;
            m_WheelNumber = i_WheelNumber;
        }

        /// <summary>
        /// An initialization function
        /// </summary>
        /// <param name="i_CreationForm">
        /// A key value Dictionary where key is the name of the member 
        /// to initialize and value is the new value
        /// <remarks>
        ///     The input form Must have a Wheel manufacturer property and a current air 
        ///     pressure property. The current air pressure Must be "pars-able" 
        ///     to float else will throw FormatException
        /// </remarks>
        /// </param>
        public void InitializeByForm(Dictionary<string, string> i_CreationForm)
        {
            bool isGetValueSucceded; 
            bool isParseSucceded;
            string wheelManufacturer;
            string wheelCurrentAirPressureString;
            float wheelCurrentAirPressure;

            isGetValueSucceded = i_CreationForm.TryGetValue(
                                                k_WheelManufacturerKey + 
                                                k_Delimiter + 
                                                m_WheelNumber, 
                                                out wheelManufacturer);
            if (!isGetValueSucceded)
            {
                throw new FormatException("Wheel manufacturer is invalid");
            }

            isGetValueSucceded = i_CreationForm.TryGetValue(
                                                k_CurrentAirPressureKey +
                                                k_Delimiter + 
                                                m_WheelNumber, 
                                                out wheelCurrentAirPressureString);
            if (!isGetValueSucceded)
            {
                throw new FormatException("Wheel current air pressure is invalid");
            }

            isParseSucceded = float.TryParse(wheelCurrentAirPressureString, out wheelCurrentAirPressure);
            if (!isParseSucceded)
            {
                throw new FormatException("Wheel current air pressure is invalid");
            }

            InitializeByData(wheelManufacturer, wheelCurrentAirPressure);
        }

        private void InitializeByData(string i_Manufacturer, float i_CurrentAirPressure)
        {
            m_Manufacturer = i_Manufacturer;
            if (i_CurrentAirPressure < 0 || i_CurrentAirPressure > r_MaxAirPressure)
            {
                throw new ValueOutOfRangeException("Air pressure out of range", k_MinAirPressure, r_MaxAirPressure);
            }

            m_CurrentAirPressure = i_CurrentAirPressure;
        }

        /// <summary>
        /// Allows you to inflate a Wheel
        /// </summary>
        /// <param name="i_AmountOfAirToInflate">
        /// The amount air to inflate 
        ///     <remarks>
        ///         Must be larger then 0 and the sum of current air pressure in the Wheel 
        ///         and this value should not excised the max air pressure , in such a 
        ///         case will throw ValueOutOfRangeException
        ///     </remarks>
        /// </param>
        public void InflateTire(float i_AmountOfAirToInflate)
        {
            float tagetAirPressure = m_CurrentAirPressure + i_AmountOfAirToInflate;
            if (tagetAirPressure < k_MinAirPressure || tagetAirPressure > r_MaxAirPressure)
            {
                throw new ValueOutOfRangeException("Air pressure out of range", k_MinAirPressure, r_MaxAirPressure);
            }

            m_CurrentAirPressure = tagetAirPressure;
        }
                
        /// <summary>
        /// A property to get the Current Air Pressure
        /// </summary>
        public float CurrentAirPressure
        {
            get { return m_CurrentAirPressure; }
        }

        /// <summary>
        /// A property to get the Max Air Pressure
        /// </summary>
        public float MaxAirPressure
        {
            get { return r_MaxAirPressure; }
        }

        /// <summary>
        /// Return a string representation object members as pair 
        /// members name and variable value
        /// </summary>
        /// <returns>string "varName + Vehicle.k_ToStirngPairDelimiter + varValue + Vehicle.sr_ToStirngEndOfPairDelimiter"</returns>
        public override string ToString()
        {
            StringBuilder stringBuilderResult = new StringBuilder();

            stringBuilderResult.Append(wheelNumberToString());
            stringBuilderResult.Append(manufactureToString());
            stringBuilderResult.Append(maxAirPressureToString());
            stringBuilderResult.Append(currentAirPressureToString());

            return stringBuilderResult.ToString();
        }

        private string wheelNumberToString()
        {
            StringBuilder stringBuilderResult = new StringBuilder();

            stringBuilderResult.Append(k_WheelNumberKey);
            stringBuilderResult.Append(Vehicle.k_ToStirngPairDelimiter);
            stringBuilderResult.Append(m_WheelNumber);
            stringBuilderResult.Append(Vehicle.sr_ToStirngEndOfPairDelimiter);

            return stringBuilderResult.ToString();
        }

        private string manufactureToString()
        {
            StringBuilder stringBuilderResult = new StringBuilder();

            stringBuilderResult.Append(k_WheelManufacturerKey);
            stringBuilderResult.Append(Vehicle.k_ToStirngPairDelimiter);
            stringBuilderResult.Append(m_Manufacturer);
            stringBuilderResult.Append(Vehicle.sr_ToStirngEndOfPairDelimiter);

            return stringBuilderResult.ToString();
        }

        private string maxAirPressureToString()
        {
            StringBuilder stringBuilderResult = new StringBuilder();

            stringBuilderResult.Append(k_MaxAirPressureKey);
            stringBuilderResult.Append(Vehicle.k_ToStirngPairDelimiter);
            stringBuilderResult.Append(r_MaxAirPressure);
            stringBuilderResult.Append(Vehicle.sr_ToStirngEndOfPairDelimiter);

            return stringBuilderResult.ToString();
        }

        private string currentAirPressureToString()
        {
            StringBuilder stringBuilderResult = new StringBuilder();

            stringBuilderResult.Append(k_CurrentAirPressureKey);
            stringBuilderResult.Append(Vehicle.k_ToStirngPairDelimiter);
            stringBuilderResult.Append(m_CurrentAirPressure);
            stringBuilderResult.Append(Vehicle.sr_ToStirngEndOfPairDelimiter);

            return stringBuilderResult.ToString();
        }
    }
}
